package com.duoqin.guard.utils;

import com.duoqin.common.base64.Base64;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Random;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class GuardUtil {

    public static final String CHARSET = "UTF-8";
    private static final String RSA_ALGORITHM = "RSA";
    private static final String SIGNATURE_ALGORITHM = "SHA256WithRSA";
    private static final String AES_CBC_PKC_ALG = "AES/CBC/PKCS5Padding";
    private static final byte[] AES_IV = initIV(AES_CBC_PKC_ALG);

    public static final String PUBLIC_KEY = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJHSdDakYatmmA9HLlHbzuTbrYq9huT04DrHYvLP1V2TtgfkI3t6JgJvGSCyZxB4C-aCQpHWaKirA-GdKMccFQUCAwEAAQ";
    public static final String PRIVATE_KEY = "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAkdJ0NqRhq2aYD0cuUdvO5Nutir2G5PTgOsdi8s_VXZO2B-Qje3omAm8ZILJnEHgL5oJCkdZoqKsD4Z0oxxwVBQIDAQABAkAsmmDtrc4qLVFpqu4iH8fi_MbSXzJ5qeVEVWSQvL2Yx3V9WCVU1tV57eapCyk_dd6WquyYOcinJDzvjjX32DUBAiEAwjysW2IO_2vBGug811GHn9pF0H3v7qJshPdUQEadTWECIQDAMLKtcnqS2SVdh0glOxtBDhTQpG71OT0XCqGEVBOmJQIhAIsqxaNEAtLm9Zi9xLnRZIcX8OWNFhe4sGAkhWz4K0SBAiBzP8CmCjQ-w0CI6Yr16I_bXxpUU4bGPuDHZHSe6dwukQIgcsLt5O1oNqbYcVvIXr1_k9XuushcwDBeIHEpCipPDKw";


    private static byte[] initIV(String aesCbcPkcAlg) {
        Cipher cp;
        try {
            cp = Cipher.getInstance(aesCbcPkcAlg);
            int blockSize = cp.getBlockSize();
            byte[] iv = new byte[blockSize];
            for (int i = 0; i < blockSize; ++i) {
                iv[i] = 0;
            }
            return iv;

        } catch (Exception e) {
            int blockSize = 16;
            byte[] iv = new byte[blockSize];
            for (int i = 0; i < blockSize; ++i) {
                iv[i] = 0;
            }
            return iv;
        }
    }

//    public static Map<String, String> createKeys(int keySize) {
//        //为RSA算法创建一个KeyPairGenerator对象
//        KeyPairGenerator kpg;
//        try {
//            kpg = KeyPairGenerator.getInstance(RSA_ALGORITHM);
//        } catch (NoSuchAlgorithmException e) {
//            throw new IllegalArgumentException("No such algorithm-->[" + RSA_ALGORITHM + "]");
//        }
//
//        //初始化KeyPairGenerator对象,密钥长度
//        kpg.initialize(keySize);
//        //生成密匙对
//        KeyPair keyPair = kpg.generateKeyPair();
//        //得到公钥
//        Key publicKey = keyPair.getPublic();
//        String publicKeyStr = Base64.encodeBase64URLSafeString(publicKey.getEncoded());
//        //得到私钥
//        Key privateKey = keyPair.getPrivate();
//        String privateKeyStr = Base64.encodeBase64URLSafeString(privateKey.getEncoded());
//        Map<String, String> keyPairMap = new HashMap<String, String>();
//        keyPairMap.put("publicKey", publicKeyStr);
//        keyPairMap.put("privateKey", privateKeyStr);
//        RSAPublicKey rsp = (RSAPublicKey) keyPair.getPublic();
//        BigInteger bit = rsp.getModulus();
//        byte[] b = bit.toByteArray();
//        byte[] deBase64Value = Base64.encodeBase64(b);
//        String retValue = new String(deBase64Value);
//        keyPairMap.put("model", retValue);
//
//        return keyPairMap;
//    }

    public static RSAPublicKey getPublicKey(String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
        //通过X509编码的Key指令获得公钥对象
        KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKey));
        RSAPublicKey key = (RSAPublicKey) keyFactory.generatePublic(x509KeySpec);
        return key;
    }

    public static RSAPrivateKey getPrivateKey(String privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
        //通过PKCS#8编码的Key指令获得私钥对象
        KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey));
        RSAPrivateKey key = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);
        return key;
    }


    /**
     * RSA 公钥加密
     *
     * @param data      加密内容
     * @param publicKey 公钥
     * @return 加密结果
     */
    public static String publicEncrypt(String data, RSAPublicKey publicKey) {
        try {
            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            return Base64.encodeBase64URLSafeString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE,
                    data.getBytes(CHARSET), publicKey.getModulus().bitLength()));
        } catch (Exception e) {
            throw new RuntimeException("加密字符串[" + data + "]时遇到异常", e);
        }
    }

    /**
     * RSA 私钥解密
     *
     * @param data       需要解密的内容
     * @param privateKey 私钥
     * @return 解密的结果
     */
    public static String privateDecrypt(String data, RSAPrivateKey privateKey) {
        try {
            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);

            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data),
                    privateKey.getModulus().bitLength()), CHARSET);
        } catch (Exception e) {
            throw new RuntimeException("解密字符串[" + data + "]时遇到异常", e);
        }
    }

    private static byte[] rsaSplitCodec(Cipher cipher, int opmode, byte[] datas, int keySize) {
        int maxBlock = 0;
        if (opmode == Cipher.DECRYPT_MODE) {
            maxBlock = keySize / 8;
        } else {
            maxBlock = keySize / 8 - 11;
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] buff;
        int i = 0;
        try {
            while (datas.length > offSet) {
                if (datas.length - offSet > maxBlock) {
                    buff = cipher.doFinal(datas, offSet, maxBlock);
                } else {
                    buff = cipher.doFinal(datas, offSet, datas.length - offSet);
                }
                out.write(buff, 0, buff.length);
                i++;
                offSet = i * maxBlock;
            }
        } catch (Exception e) {
            throw new RuntimeException("加解密阀值为[" + maxBlock + "]的数据时发生异常", e);
        }
        byte[] resultDatas = out.toByteArray();
        try {
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return resultDatas;
    }

    public static String sign(byte[] data, String privateKey) throws Exception {
        byte[] keyBytes = Base64.decodeBase64(privateKey);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
        PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initSign(privateK);
        signature.update(data);
        return Base64.encodeBase64URLSafeString(signature.sign());
    }


    public static boolean verify(byte[] data, String publicKey, String sign)
            throws Exception {
        byte[] keyBytes = Base64.decodeBase64(publicKey);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
        PublicKey publicK = keyFactory.generatePublic(keySpec);
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initVerify(publicK);
        signature.update(data);
        return signature.verify(Base64.decodeBase64(sign));
    }

    /**
     * AES 解密
     *
     * @param content  解密的内容
     * @param password 解密的密码
     * @return 解密的结果
     */
    public static String decrypt4Base64(String content, String password) throws Exception {
        byte[] byteContent = Base64.decodeBase64(content);
        byte[] enCodeFormat = password.getBytes(CHARSET);
        SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
        Cipher cipher = Cipher.getInstance(AES_CBC_PKC_ALG);
        cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(AES_IV));
        byte[] result = cipher.doFinal(byteContent);
        return new String(result, CHARSET);

    }

    /**
     * AES 加密
     *
     * @param content  加密的内容
     * @param password 加密的密码
     * @return 加密结果
     */
    public static String encrypt4Base64(String content, String password) throws Exception {
        byte[] bytePwd = password.getBytes(CHARSET);
        SecretKeySpec key = new SecretKeySpec(bytePwd, "AES");
        Cipher cipher = Cipher.getInstance(AES_CBC_PKC_ALG);
        byte[] byteContent = content.getBytes(CHARSET);
        cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(AES_IV));
        byte[] result = cipher.doFinal(byteContent);
        return Base64.encodeBase64URLSafeString(result);

    }

    /**
     * 获取16位随机数
     *
     * @return 16位随机数
     */
    public static String getRandom() {
        StringBuilder sb = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < 16; i++) {
            sb.append("1234567890qwertyuiopasdfghjklzxcvbnm".charAt(random
                    .nextInt("1234567890qwertyuiopasdfghjklzxcvbnm".length())));
        }
        return sb.toString();
    }
}
